#include "CompositeIFstream.h"
#include <tchar.h>
#include <atlconv.h>

#include <STRING>

using namespace std;

#define BYTES_PER_FRAME 0x7FFFFFFF

CCompositeIFstream::CCompositeIFstream(void)
{
	m_nNumFrames = 0;
	m_nResolution = 0;
	m_nResolution3 = 0;
	m_nCurrentFrameID = 0;
	m_nNumFramesPack = 0;
}

CCompositeIFstream::~CCompositeIFstream(void)
{
}

bool CCompositeIFstream::Open(const wchar_t *fn)
{
	wstring filename = fn;
	wstring::size_type pos = filename.rfind('.');	
	wstring name = filename.substr(0, pos);
	wstring ext = L"";	
	if( pos!=filename.npos )
	{
		ext = filename.substr(pos);
	}

	ifstream* input = new ifstream;
	m_Streams.push_back(input);	
	m_Streams[0]->open( fn, ios::in|ios::binary );
	if( m_Streams[0]->fail() )
	{
		return false;
	}

	m_Streams[0]->read( (char*)&m_nResolution, sizeof(int) );
	m_Streams[0]->read( (char*)&m_nNumFrames, sizeof(int) );
	
	m_nResolution3 = m_nResolution*m_nResolution*m_nResolution;	

	int count = 0;
	int pack_num_frames = BYTES_PER_FRAME/(m_nResolution3*sizeof(float));		
	int num_packs = min(pack_num_frames, m_nNumFrames-count);
	count += num_packs;
	int pack_id = 1;		
	while( count<m_nNumFrames )
	{
		wchar_t pack_id_str[255];
		swprintf_s( pack_id_str, 255, L"#%02d", pack_id ); 
		wstring new_file_name = name+pack_id_str+ext;
		input = new ifstream;
		m_Streams.push_back(input);
		m_Streams[pack_id]->open( new_file_name.c_str(), ios::in|ios::binary );
		if(m_Streams[pack_id]->fail())
		{
			return false;
		}
		num_packs = min(pack_num_frames, m_nNumFrames-count);		
		count += num_packs;
		pack_id++;		
	}
	m_nNumFramesPack = pack_num_frames;
	return true;
}

bool CCompositeIFstream::Open(const char *filename)
{
	wchar_t fn[255];
	size_t converted;
	mbstowcs_s( &converted, fn, 255, filename, 255);
	return Open(fn);
}

void CCompositeIFstream::Close()
{
	for(unsigned int i=0; i<m_Streams.size(); i++)
	{
		if(m_Streams[i]->is_open())
		{
			m_Streams[i]->close();
		}
		delete m_Streams[i];
	}
	m_Streams.clear();
}

void CCompositeIFstream::Reset()
{
	m_nCurrentFrameID = 0;	
	for(unsigned int i=0; i<m_Streams.size(); i++)
	{
		m_Streams[i]->seekg(0);
	}
	m_Streams[0]->seekg(2*sizeof(int));
}

float CCompositeIFstream::Get(long long id)
{
	int frame_id = (int)(id/m_nResolution3);	
	int pack_id = frame_id/m_nNumFramesPack;
	ifstream::pos_type pos = (int)(id - pack_id*m_nResolution3*m_nNumFramesPack)*sizeof(float);

	m_Streams[pack_id]->seekg(pos);
	float value;
	m_Streams[pack_id]->read( (char*) &value, sizeof(float) );
	return value;
}

void CCompositeIFstream::GetFrame( float* frame_data )
{
	if( m_nCurrentFrameID == m_nNumFrames )
		return;
	int current_pack_id = m_nCurrentFrameID/m_nNumFramesPack;
	m_Streams[current_pack_id]->read( (char*) frame_data, sizeof(float)*m_nResolution3 );
	m_nCurrentFrameID++;	
}

void CCompositeIFstream::GetFrame(unsigned int frame_id, float *& frame_data)
{
	if( int(frame_id)>=m_nNumFrames )
	{
		frame_data = NULL;
		return;
	}
	if( NULL==frame_data )
	{
		frame_data = new float[m_nResolution3];
	}	
	m_nCurrentFrameID = frame_id;	
	int current_pack_id = m_nCurrentFrameID/m_nNumFramesPack;	
	int fid = frame_id - current_pack_id * m_nNumFramesPack;	
	ifstream::pos_type start_pos = fid * m_nResolution3 * sizeof(float);
	if( 0==current_pack_id )
		start_pos += 2*sizeof(int);
	m_Streams[current_pack_id]->seekg(start_pos);	
	m_Streams[current_pack_id]->read( (char*) frame_data, sizeof(float)*m_nResolution3 );	
}


